package wechat.base.snd
import java.util.Collection
import java.util.Date
import org.json.JSONArray
import org.json.JSONObject
import wechat.base.snd.encoding.JsonPut
import wechat.base.snd.encoding.MsgEncoding
import wechat.base.snd.util.ExecGet
import wechat.base.snd.util.ExecPost
import wechat.base.snd.util.PostFile
import java.net.URLEncoder
import org.eclipse.xtend.lib.annotations.Accessors
import org.json.JSONException

//代表微信号中的一个应用
//@Data
class WCApplication{
	@Accessors String CORP_ID
	@Accessors String SECRET
	@Accessors String AGENT_ID
	String TOKEN=null
	String authurl
	new (String corp_id, String secret, String agent_id){
		CORP_ID = corp_id
		SECRET = secret
		AGENT_ID = agent_id
		authurl = WECHAT_AUTH_URL + CORP_ID +'&redirect_uri='
	}
	static String WECHAT_PLATFORM_URL = "https://qyapi.weixin.qq.com";
	static Long TOKEN_EXPIRATION_TIME = 7200*1000l //7200S with a buffer
	static Date tokenTime = new Date
	
	static String WECHAT_AUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=";
//https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=AGENTID&state=STATE#wechat_redirect
	
	def String getToken() { 
		if (((new Date).getTime()-tokenTime.getTime())>=TOKEN_EXPIRATION_TIME||TOKEN==null){
			try{
				print("**********get token*****")
				val tokenUrl = WECHAT_PLATFORM_URL + "/cgi-bin/gettoken?corpid=" + CORP_ID + "&corpsecret=" + SECRET;
				val JSONObject js = new JSONObject(ExecGet::excuteGet(tokenUrl));
				js.getString("access_token")
				this.TOKEN=js.getString("access_token")
				tokenTime = new Date
				println('token='+TOKEN)
			}
			catch(Exception e){
				println("**********Failed to get token*****")
				TOKEN = null
				e.printStackTrace
			}
		}
		TOKEN
	}
	def getApplicationUrl(){
		WECHAT_PLATFORM_URL + "/cgi-bin/message/send?access_token="+ token
	}
	def getApplicationMediaUrl(){
		WECHAT_PLATFORM_URL + "/cgi-bin/media/upload?access_token="+ token
	}
	def WCNews createNews(){
		new WCNews(this)
	}
	def WCMPNews createMPNews(){
		new WCMPNews(this)
	}
	//上传文件，图片等，取得mediaID
	def WCMediaInfo uploadTmpFile(String filePath){
		new WCMediaInfo(PostFile::uploadFile(applicationMediaUrl, filePath, "image"))
	}
	
	//Https请求方式：GET  https://qyapi.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN&agentid=AGENTID
	def deleteMenu(){
		ExecGet::excuteGet('https://qyapi.weixin.qq.com/cgi-bin/menu/delete?access_token='+getToken+'&agentid='+AGENT_ID)
	}
	
	//Https请求方式: POST  https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN&agentid=AGENTID
	def String createMenu(WCMenu menu){
		ExecPost::excuteJsonPost('https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token='+getToken+'&agentid='+AGENT_ID, menu.build.toString)
	}	
	
	//Https请求方式：GET  https://qyapi.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN&agentid=AGENTID
	def String getMenuInfo(){
		val url = 'https://qyapi.weixin.qq.com/cgi-bin/menu/get?access_token='+getToken+'&agentid='+AGENT_ID
		ExecGet::excuteGet(url)
	}
	
//https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=AGENTID&state=STATE#wechat_redirect	
	def String buildAuthConnection(String redirectUrl,String state){
//		URLEncoder::encode(redirectUrl, "utf-8")
		println('URLEncoder::encode(redirectUrl, "utf-8"):::'+URLEncoder::encode(redirectUrl, "utf-8"))
		authurl + URLEncoder::encode(redirectUrl, "utf-8") + '&response_type=code&scope=snsapi_base'+'&agentid='+AGENT_ID+'&state='+state
	}
	
//	//Https请求方式：GET  https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE
//	def String getUserInfo(String code){
//		var url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token="+getToken+"&code="+code;
//		ExecGet::excuteGet(url)
//	}
	
	def String getUserId(String code){
		println("***********enter in getUserId**************")
		var url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token="+getToken+"&code="+code;
		println("*********url*********"+url)
		var result = ExecGet::excuteGet(url)
		println("*************UserInfo JSONObject*************"+result)
		try{		
			val js = new JSONObject(result);
//			if (js != null){
//				try{
//					if (js?.getString("errcode") == "40029"){
//						var newurl = url.substring(0, url.indexOf("&code=")).concat("&code=").concat(code)
//						println("*********newurl*********"+newurl)
//						result = ExecGet::excuteGet(newurl)
//						println("*************new result*************"+result)
//						val JSONObject newjs = new JSONObject(result);
//						return newjs?.getString('userid')
//					}
//				} catch (JSONException e){
//					println("*********code is valid")
//				}
//			}
			js?.getString('UserId')
		} catch (JSONException e) {
			e.printStackTrace();
			null
		}
	}
}

abstract class WCMessage{
	protected WCApplication application
	protected MsgEncoding encoding
	
	new(WCApplication application){
		this.application = application
		encoding = new MsgEncoding()=>[
			setSafe("0");
			setToAgentid(application.AGENT_ID);			
		]
	}

	def protected void buildContents()
	def send2Users(Iterable<String> users){
		encoding.setToUsers(users)
		buildContents()
		ExecPost::excuteJsonPost(application.applicationUrl,encoding.toString)
	}
}

class WCNews extends WCMessage{
	new(WCApplication application) {
		super(application)
		encoding.setMsgType("news");
	}
	
	Collection<WCNewsItem> items = newArrayList
	
	def WCNewsItem withItem(String title){
		new WCNewsItem(title)=>[
			items.add(it)
		]
	}
	
	override buildContents(){
		val JsonPut contents = new JsonPut();
		val JSONArray ja = new JSONArray();
		for (WCNewsItem obj : items)
			ja.put(obj.toJson);
		contents=>[
			putObj("articles", ja);
		]
		encoding.setNews(contents)
	}
}

class WCNewsItem{
	@Accessors String title
	@Accessors String description
	@Accessors String url
	@Accessors String picurl
	
	new(String title){
		this.title = title
	}
	
	def toJson(){
		val JsonPut article = new JsonPut()
		article.putObj("title", title);
		if(description!=null)article.putObj("description", description);
		if(url!=null)article.putObj("url", url);
		if(picurl!=null)article.putObj("picurl", picurl);
		article
	}
}

class WCMediaInfo{
	@Accessors String type
	@Accessors String media_id
	@Accessors String created_at
	
	private JSONObject js
	
	new(String jsonStr){
		js = new JSONObject(jsonStr)
		type= js.getString("type")
		media_id= js.getString("media_id")
		created_at= js.getString("created_at")
	}
}


class WCMPNews extends WCMessage{
	new(WCApplication application) {
		super(application)
		encoding.setMsgType("mpnews");
	}
	
	Collection<WCMPNewsItem> items = newArrayList
	
	def WCMPNewsItem withItem(String title){
		new WCMPNewsItem(title)=>[
			items.add(it)
		]
	}
	
	override buildContents(){
		val JsonPut contents = new JsonPut();
		val JSONArray ja = new JSONArray();
		for (WCMPNewsItem obj : items)
			ja.put(obj.toJson);
		contents=>[putObj("articles", ja);]
		encoding.setMpNews(contents)
	}
}
class WCMPNewsItem{
	@Accessors String title
	@Accessors String thumb_media_id
	@Accessors String author
	@Accessors String content_source_url
	@Accessors String content
	@Accessors String digest
	@Accessors String show_cover_pic
	
	new(String title){
		this.title = title
		show_cover_pic="0"
	}
	
	def toJson(){
		val JsonPut article = new JsonPut()
		article.putObj("title", title);
		article.putObj("thumb_media_id", thumb_media_id);
		article.putObj("author", author);
		article.putObj("content_source_url", content_source_url);
		article.putObj("content", content);
		article.putObj("digest", digest);
		article.putObj("show_cover_pic", show_cover_pic);
		article
	}
}
